package photo

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/service/backend/common/utils/pointy"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/types/forum"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetPhotoListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetPhotoListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPhotoListLogic {
	return &GetPhotoListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetPhotoListLogic) GetPhotoList(in *forum.BaseListReq) (*forum.PostListResp, error) {
	if in.Filter == nil || len(*in.Filter) == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)

	logrus.Info(fmt.Sprintf("GetPhotoList preloadMap: %+v", preloadMap))

	logrus.Info(fmt.Sprintf("GetPhotoList eagerLoadMap: %+v", eagerLoadMap))

	forumPostEntityName := model.RpcEntityNames.ForumPost
	_, hasSettingMap := model.RpcEntityPreloadMap[forumPostEntityName]
	if !hasSettingMap {
		return &forum.PostListResp{}, nil
	}

	forumPostRepositoryName := model.RepositoryNames.ForumPost
	columnMap, hasColumnMap := model.RepositoryPreloadMap[forumPostRepositoryName]
	if !hasColumnMap {
		return &forum.PostListResp{}, nil
	}

	var selectCols []string
	if preloadFields, hasPreloadFields := preloadMap[forumPostEntityName]; hasPreloadFields {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	logrus.Info(fmt.Sprintf("GetPhotoList filterMap: %+v", filterMap))
	if filterMap == nil {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	logrus.Info(fmt.Sprintf("GetPhotoList orderBy: %s", orderBy))
	if len(orderBy) == 0 {
		orderBy = model.ForumPostColumns.PostModifiedDate + " DESC"
	}

	res, count, err := l.svcCtx.Post.GetList(l.ctx, model.M{
		"offset": in.Offset,
		"limit":  in.Limit,
		// "search":  in.Search,
		"orderBy": orderBy,
		"select":  strings.Join(selectCols, ","),
	}, 2, filterMap)
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp := &forum.PostListResp{
		HasNextPage:     &hasNextPage,
		HasPreviousPage: &hasPreviousPage,
	}

	var total int64
	if len(res) > 0 {
		var ids []any
		for _, v := range res {
			ids = append(ids, v.PostID)
		}

		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, hasEagerLoadEntities := eagerLoadMap[forumPostEntityName]; hasEagerLoadEntities {
			for _, entity := range eagerLoadEntities {
				if entity == "total" {
					_, total, err = l.svcCtx.Post.GetList(l.ctx, model.M{}, 0, filterMap)
					if err != nil {
						total = 0
					}
					continue
				}

				if entity == "photoTotal" {
					total, err = l.svcCtx.Post.GetMediaCount(l.ctx, filterMap)
					if err != nil {
						total = 0
					}
					continue
				}

				if entitySettingMap, hasEntitySettingMap := model.RpcEntityPreloadMap[entity]; hasEntitySettingMap {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idMediaMap := make(map[uint64][]*forum.ForumMediaInfo)
		forumMediaEntityName := model.RpcEntityNames.ForumMedia
		forumMediaRepositoryName := model.RepositoryNames.ForumMedia
		if _, hasEntitySettingMap := subEntitySettingMap[forumMediaEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[forumMediaEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[forumMediaRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				var subSelectCols []string = modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				mediaFilterMap := make(map[string]map[string][]any)
				mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
					"in": ids,
				}
				mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
					"equalTo": []any{globalkey.AttachmentLogTypeForumPost},
				}
				var pageSize uint64 = uint64(in.Limit) * uint64(3)
				if strings.Contains(","+strings.Join(subSelectCols, ",")+",", ","+model.ForumAttachmentRelationshipColumns.AttachmentOrder+",") {
					pageSize = 0
				}
				subSelectCols = append(subSelectCols, model.ForumAttachmentRelationshipColumns.ObjectID)
				var orderBy string = model.ForumAttachmentRelationshipColumns.AttachmentOrder
				mediaList, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
					"orderBy":  orderBy,
					"pageSize": pageSize,
					"select":   strings.Join(subSelectCols, ","),
				}, -1, mediaFilterMap)
				if err != nil {
					return nil, err
				}

				if len(mediaList) > 0 {
					for _, v := range mediaList {
						idMediaMap[v.ObjectID] = append(idMediaMap[v.ObjectID], &forum.ForumMediaInfo{
							Uid:       pointy.GetPointer(v.AttachmentRelationshipID),
							Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
							Uri:       pointy.GetPointer(v.AttachmentSource),
							Url:       pointy.GetPointer(v.AttachmentImageURL),
							Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
							Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
							AltText:   pointy.GetPointer(v.AttachmentImageAlt),
							Meta:      pointy.GetPointer(v.AttachmentImageMeta),
						})
					}
				}
			}
		}

		idMetaMap := make(map[uint64][]*forum.ForumMetaInfo)
		forumPostMetaEntityName := model.RpcEntityNames.ForumPostMeta
		if entitySettingMap, hasEntitySettingMap := subEntitySettingMap[forumPostMetaEntityName]; hasEntitySettingMap {
			if subPreloadFields, hasSubPreloadFields := preloadMap[forumPostMetaEntityName]; hasSubPreloadFields {
				var metaKeys []any
				metaKeyMap := make(map[string]string)
				for _, field := range subPreloadFields {
					fieldSetting, hasFieldSetting := entitySettingMap[field]
					if hasFieldSetting && len(fieldSetting.Name) > 0 {
						metaKeys = append(metaKeys, fieldSetting.Name)
						metaKeyMap[fieldSetting.Name] = field
					}
				}
				if len(metaKeys) > 0 {
					metaFilterMap := make(map[string]map[string][]any)
					metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
						"in": ids,
					}
					metaFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
						"in": metaKeys,
					}
					metaList, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
					if err != nil && err != model.ErrNotFound {
						return nil, err
					}

					if len(metaList) > 0 {
						for _, v := range metaList {
							key := v.MetaKey
							if len(key) > 0 && v.MetaValue.Valid {
								val := v.MetaValue.String
								if key == "_note" || key == "_grade" {
									continue
								}

								if field, hasField := metaKeyMap[key]; hasField {
									idMetaMap[v.PostID] = append(idMetaMap[v.PostID], &forum.ForumMetaInfo{
										Id:    pointy.GetPointer(v.MetaID),
										Key:   pointy.GetPointer(field),
										Value: pointy.GetPointer(val),
									})
								}
							}
						}
					}
				}
			}
		}

		for _, v := range res {
			var media []*forum.ForumMediaInfo
			if ms, ok := idMediaMap[v.PostID]; ok {
				media = ms[:]
			}
			var meta []*forum.ForumMetaInfo
			if ms, ok := idMetaMap[v.PostID]; ok {
				meta = ms[:]
			}
			resp.List = append(resp.List, &forum.PostInfo{
				Id:            pointy.GetPointer(v.PostID),
				ForumId:       pointy.GetPointer(v.ForumID),
				AuthorId:      pointy.GetPointer(v.PostAuthorID),
				TopicId:       pointy.GetPointer(v.TopicID),
				ParentId:      pointy.GetPointer(v.ParentID),
				Status:        pointy.GetPointer(uint32(v.PostStatus)),
				Sticky:        pointy.GetPointer(uint32(v.Sticky)),
				CommentStatus: pointy.GetPointer(uint32(v.CommentStatus)),
				CommentCount:  pointy.GetPointer(uint32(v.CommentCount)),
				PhotoCount:    pointy.GetPointer(uint32(v.PhotoCount)),
				CreatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostDate, "")),
				UpdatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostModifiedDate, "")),
				Author: &forum.ForumAuthorInfo{
					Id:        pointy.GetPointer(v.PostAuthorID),
					Name:      pointy.GetPointer(v.PostAuthorNickname),
					Email:     pointy.GetPointer(v.PostAuthorEmail),
					Avatar:    pointy.GetPointer(v.PostAuthorAvatar),
					Ip:        pointy.GetPointer(v.PostAuthorIP),
					Level:     pointy.GetPointer(uint32(v.PostAuthorRankID)),
					Anonymous: pointy.GetPointer(uint32(v.PostAuthorAnonymous)),
				},
				Media: media,
				Meta:  meta,
			})
		}
	}

	resp.Total = uint64(total)

	return resp, nil
}
